#pragma once

#include <string>
#include <mutex>
#include <atomic>
#include "Callbacks.h"
#include "TcpConnection.h"

class EventLoop;
class InetAddress;
class Connector;
typedef std::shared_ptr<Connector> ConnectorPtr;

class TcpClient
{
public:
	TcpClient(EventLoop* loop,
		const InetAddress& serverAddr,
		const string& nameArg);
	~TcpClient();		// force out-line dtor, for scoped_ptr members.

	void connect();
	void disconnect();
	void stop();

	TcpConnectionPtr connnection()const
	{
		std::unique_lock<std::mutex> lock(m_mutex);
		return m_ptrConnection;
	}

	EventLoop* getLoop()const{ return m_pLoop; }
	bool retry()const;
	void enableRetry(){ m_bRetry = true; }

	const std::string& name()const{ return m_strName; }

	/// Set connection callback.
	/// Not thread safe.
	void setConnectionCallback(const ConnectionCallback& cb)
	{
		m_connCallback = cb;
	}

	/// Set message callback.
	/// Not thread safe.
	void setMessageCallback(const MessageCallback& cb)
	{
		m_msgCallback = cb;
	}

	/// Set write complete callback.
	/// Not thread safe.
	void setWriteCompleteCallback(const WriteCompleteCallback& cb)
	{
		m_writeCompeleteCallback = cb;
	}
private:
	///not thread safe, but in loop
	void newConnceton(int sockfd);
	///not thread safe,but in loop
	void removeConnection(const TcpConnectionPtr& conn);

	EventLoop* m_pLoop;
	ConnectorPtr m_ptrConnector;	//avoid revealing Connector
	const std::string m_strName;
	ConnectionCallback m_connCallback;
	MessageCallback m_msgCallback;
	WriteCompleteCallback m_writeCompeleteCallback;
	std::atomic<bool> m_bRetry;
	std::atomic<bool> m_bConnect;
	//always in loop thread
	int m_nextConnId;				//only use in Loop thread
	mutable std::mutex m_mutex;
	TcpConnectionPtr m_ptrConnection;
};
